Bring in support for Garmin special data (garmin_fs).
authoroliskoli <oliskoli@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Wed, 5 Apr 2006 17:44:38 +0000 (17:44 +0000)
committeroliskoli <oliskoli@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Wed, 5 Apr 2006 17:44:38 +0000 (17:44 +0000)
gpsbabel/defs.h
gpsbabel/garmin_fs.c [new file with mode: 0644]
gpsbabel/garmin_fs.h [new file with mode: 0644]

index 0260ece128d7fe36afc0ca01430c48451cd3f091..85331995d39987575ccfebbbdcc8e4e99a319bc2 100644 (file)
@@ -29,6 +29,7 @@
 #include "gbtypes.h"
 #include "cet.h"
 #include "cet_util.h"
+#include "inifile.h"
 
 
 /*
@@ -119,6 +120,7 @@ typedef struct {
        int no_smart_names;
        cet_cs_vec_t *charset;
        char *charset_name;
+       inifile_t *inifile;
 } global_options;
 
 extern global_options global_opts;
@@ -218,6 +220,7 @@ fs_xml *fs_xml_alloc( long type );
 #define FS_AN1L 0x616e316cL
 #define FS_AN1V 0x616e3176L
 #define FS_OZI 0x6f7a6900L
+#define FS_GMSD 0x474d5344L    /* GMSD = Garmin specific data */
 
 /*
  * Misc bitfields inside struct waypoint;
@@ -320,6 +323,7 @@ typedef struct {
        queue waypoint_list;    /* List of child waypoints */
        char *rte_name;
        char *rte_desc;
+       char *rte_url;
        int rte_num;
        int rte_waypt_ct;               /* # waypoints in waypoint list */
        format_specific_data *fs;
@@ -555,6 +559,8 @@ void is_fatal(const int condition, const char *, ...) PRINTFLIKE(2, 3);
 void warning(const char *, ...) PRINTFLIKE(1, 2);
 
 ff_vecs_t *find_vec(char * const, char **);
+void assign_vec_option(const char *vecname, arglist_t *ap, const char *val);
+void disp_vec_options(const char *vecname, arglist_t *ap);
 void disp_vecs(void);
 void exit_vecs(void);
 void disp_formats(int version);
diff --git a/gpsbabel/garmin_fs.c b/gpsbabel/garmin_fs.c
new file mode 100644 (file)
index 0000000..14c4f47
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+  
+    Implementation of special data used by Garmin products.
+    
+    Copyright (C) 2006 Olaf Klein, o.b.klein@t-online.de
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "defs.h"
+#include "garmin_fs.h"
+#include "garmin_tables.h"
+#include "inifile.h"
+
+#define MYNAME "garmin_fs"
+
+garmin_fs_t *
+garmin_fs_alloc(const int protocol)
+{
+       garmin_fs_t *result = NULL;
+
+       result = (garmin_fs_t *)xcalloc(1, sizeof(*result));
+       result->fs.type = FS_GMSD;
+       result->fs.copy = (fs_copy) garmin_fs_copy;
+       result->fs.destroy = garmin_fs_destroy;
+       result->fs.next = NULL;
+       
+       result->protocol = protocol;
+       
+       return result;
+}
+
+void 
+garmin_fs_destroy(void *fs)
+{
+       garmin_fs_t *data = (garmin_fs_t *) fs;
+       if (data != NULL)
+       {
+               garmin_ilink_t *ilinks;
+               
+               if (data->city != NULL) xfree(data->city);
+               if (data->facility != NULL) xfree(data->facility);
+               if (data->state != NULL) xfree(data->state);
+               if (data->cc != NULL) xfree(data->cc);
+               if (data->cross_road != NULL) xfree(data->cross_road);
+               if ((ilinks = data->ilinks) != NULL) {
+                       ilinks->ref_count--;
+                       if (ilinks->ref_count <= 0) {
+                               while (ilinks != NULL) {
+                                       garmin_ilink_t *tmp = ilinks;
+                                       ilinks = ilinks->next;
+                                       xfree(tmp);
+                               }
+                       }
+               }
+               xfree(data);
+       }
+}
+
+void garmin_fs_copy(garmin_fs_t **dest, garmin_fs_t *src)
+{
+       if (src == NULL)
+       {
+               *dest = NULL;
+               return;
+       }
+       *dest = (garmin_fs_t *) xmalloc(sizeof(*src));
+       
+       /* do not copy interlinks, only increment the refrence counter */
+       if (src->ilinks != NULL) src->ilinks->ref_count++;
+       
+       memcpy(*dest, src, sizeof(*src));
+       
+       (*dest)->city = (src->city != NULL) ? xstrdup(src->city) : NULL;
+       (*dest)->facility = (src->facility != NULL) ? xstrdup(src->facility) : NULL;
+       (*dest)->state = (src->state != NULL) ? xstrdup(src->facility) : NULL;
+       (*dest)->cc = (src->cc != NULL) ? xstrdup(src->cc) : NULL;
+       (*dest)->cross_road = (src->cross_road != NULL) ? xstrdup(src->cross_road) : NULL;
+       (*dest)->addr = (src->addr != NULL) ? xstrdup(src->addr) : NULL;
+}
+
+/* GPX - out */
+
+void 
+garmin_fs_xml_fprint(FILE *ofd, const waypoint *waypt)
+{
+       garmin_fs_t *gmsd = GMSD_FIND(waypt);
+       if (gmsd == NULL) return;
+       
+       if ((gmsd->flags.category && gmsd->category) || 
+            gmsd->flags.depth || 
+            gmsd->flags.proximity || 
+            gmsd->flags.temperature || 
+            gmsd->flags.display)
+       {
+               int space = 1;
+               
+               fprintf(ofd, "%*s<extensions>\n", space++ * 2, "");
+               fprintf(ofd, "%*s<gpxx:WaypointExtension xmlns:gpxx=\"" \
+                       "http://www.garmin.com/xmlschemas/GpxExtensions/v2\" " \
+                       "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
+                       "xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/GpxExtensions/v2 " \
+                       "http://www.garmin.com/xmlschemas/GpxExtensions/v2/GpxExtensionsv2.xsd\">\n", space++ * 2, "");
+               if (gmsd->flags.proximity)
+                       fprintf(ofd, "%*s<gpxx:Proximity>%.6f</gpxx:Proximity>\n", space * 2, "", gmsd->proximity);
+               if (gmsd->flags.temperature)
+                       fprintf(ofd, "%*s<gpxx:Temperature>%.6f</gpxx:Temperature>\n", space * 2, "", gmsd->temperature);
+               if (gmsd->flags.depth)
+                       fprintf(ofd, "%*s<gpxx:Depth>%.6f</gpxx:Depth>\n", space * 2, "", gmsd->depth);
+               if (gmsd->flags.display)
+               {
+                       char *cx;
+                       switch(gmsd->display)
+                       {
+                               case gt_display_mode_symbol: 
+                                       cx = "SymbolOnly"; 
+                                       break;
+                               case gt_display_mode_symbol_and_comment: 
+                                       cx = "SymbolAndDescription"; 
+                                       break;
+                               default: 
+                                       cx = "SymbolAndName"; 
+                                       break;
+                       }
+                       fprintf(ofd, "%*s<gpxx:DisplayMode>%s</gpxx:DisplayMode>\n", space * 2, "", cx);
+               }
+               if (gmsd->flags.category && gmsd->category)
+               {
+                       int i;
+                       gbuint16 cx = gmsd->category;
+                       fprintf(ofd, "%*s<gpxx:Categories>\n", space++ * 2, "");
+                       for (i = 0; i < 16; i++) 
+                       {
+                               if (cx & 1)
+                                       fprintf(ofd, "%*s<gpxx:Category>Category %d</gpxx:Category>\n", space*2, "", i+1);
+                               cx = cx >> 1;
+                       }
+                       fprintf(ofd, "%*s</gpxx:Categories>\n", --space * 2, "");
+               }
+               fprintf(ofd, "%*s</gpxx:WaypointExtension>\n", --space * 2, "");
+               fprintf(ofd, "%*s</extensions>\n", --space * 2, "");
+       }
+       
+}
+
+void
+garmin_fs_xml_convert(const int base_tag, int tag, const char *cdatastr, waypoint *waypt)
+{
+       garmin_fs_t *gmsd;
+
+       gmsd = GMSD_FIND(waypt);
+       if (gmsd == NULL) {
+               gmsd = garmin_fs_alloc(-1);
+               fs_chain_add(&waypt->fs, (format_specific_data *) gmsd);
+       }
+       
+       tag -= base_tag;
+/*
+       tt_garmin_extension, -> 0
+       tt_garmin_waypt_extension, -> 1
+       tt_garmin_proximity, -> 2
+       tt_garmin_temperature,-> 3
+       tt_garmin_depth, -> 4
+       tt_garmin_display_mode, -> 5
+       tt_garmin_categories, -> 6
+       tt_garmin_category, -> 7
+*/
+       switch(tag) {
+       case 2: GMSD_SET(proximity, atof(cdatastr)); break;
+       case 3: GMSD_SET(temperature, atof(cdatastr)); break;
+       case 4: GMSD_SET(depth, atof(cdatastr)); break;
+       case 5: if (case_ignore_strcmp(cdatastr, "SymbolOnly") == 0) {
+                       GMSD_SET(display, gt_display_mode_symbol);
+               }
+               else if (case_ignore_strcmp(cdatastr, "SymbolAndDescription") == 0) {
+                       GMSD_SET(display, gt_display_mode_symbol_and_comment);
+               }
+               else {
+                       GMSD_SET(display, gt_display_mode_symbol_and_name);
+               }
+               break;
+       case 7: if ( ! garmin_fs_merge_category(cdatastr, waypt)) {
+                       warning(MYNAME ": Unable to convert category \"%s \"!\n", cdatastr);
+               }
+               break;
+       }
+}
+
+unsigned char 
+garmin_fs_convert_category(const char *category_name, gbuint16 *category)
+{
+       int i;
+       int cat = 0;
+       
+       if ((case_ignore_strncmp(category_name, "Category ", 9) == 0) &&
+           (1 == sscanf(category_name + 9, "%d", &i)) && 
+           (i >= 1) && (i <= 16)) {
+               cat = (1 << --i);
+       }
+       else if (global_opts.inifile != NULL) {
+               for (i = 0; i < 16; i++) {
+                       char *c;
+                       char key[3];
+                       
+                       snprintf(key, sizeof(key), "%d", i + 1);
+                       c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key);
+                       if ((c != NULL) && (case_ignore_strcmp(c, category_name) == 0)) {
+                               cat = (1 << i);
+                               break;
+                       }
+               }
+       }
+       if (cat == 0) {
+               return 0;
+       } 
+       else {
+               *category = cat;
+               return 1;
+       }
+}
+
+unsigned char
+garmin_fs_merge_category(const char *category_name, waypoint *waypt)
+{
+       gbuint16 cat;
+       garmin_fs_t *gmsd;
+       
+       if (!garmin_fs_convert_category(category_name, &cat)) {
+               return 0;
+       }
+       
+       gmsd = GMSD_FIND(waypt);
+       cat = cat | ( GMSD_GET(category, 0) );
+       
+       if (gmsd == NULL) {
+               gmsd = garmin_fs_alloc(-1);
+               fs_chain_add(&waypt->fs, (format_specific_data *) gmsd);
+       }
+       GMSD_SET(category, cat);
+       return 1;
+}
diff --git a/gpsbabel/garmin_fs.h b/gpsbabel/garmin_fs.h
new file mode 100644 (file)
index 0000000..0c85b44
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+  
+    Implementation of special data used by Garmin products.
+    
+    Copyright (C) 2006 Olaf Klein, o.b.klein@t-online.de
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#ifndef GARMIN_FS_H
+#define GARMIN_FS_H
+
+#include <ctype.h>
+#include "defs.h"
+
+/* this order is used by most devices */
+/* typedef enum {
+       garmin_display_symbol_and_name = 0,
+       garmin_display_symbol_only = 1,
+       garmin_display_symbol_and_description = 2
+} garmin_display_t;
+*/
+
+/* macros */
+
+#define GMSD_FIND(a) (garmin_fs_t *) fs_chain_find((a)->fs, FS_GMSD)
+
+/* GMSD_GET(a,b): a = any gmsd field, b = default value */
+#define GMSD_GET(a,b) ((gmsd) && (gmsd->flags.a)) ? (gmsd->a) : (b)
+
+/* GMSD_SET(a,b): a = numeric gmsd field, b = numeric source */
+#define GMSD_SET(a,b) if (gmsd) {gmsd->a = (b); gmsd->flags.a = 1; }
+
+/* GMSD_SETSTR(a,b): a = gmsd field, b = null terminated source */
+#define GMSD_SETSTR(a,b) if (gmsd && (b) && (b)[0]) { gmsd->a = xstrdup((b)); gmsd->flags.a = 1; }
+
+/* GMSD_SETNSTR(a,b,c): a = gmsd field, b = source, c = sizeof(source) */
+#define GMSD_SETNSTR(a,b,c) if (gmsd && (b) && (b)[0]) { gmsd->a = xstrndup((b),(c)); gmsd->flags.a = 1; }
+
+/* GMSD_GETNSTR(a,b,c): a = gmsd field, b = target, c = sizeof(target) */
+#define GMSD_GETNSTR(a,b,c) if (gmsd && gmsd->flags.a) strncpy((b),gmsd->a,(c))
+
+typedef struct garmin_ilink_s {
+       int ref_count;
+       double lat, lon;
+       struct garmin_ilink_s *next;
+} garmin_ilink_t;
+
+typedef struct {
+       unsigned int icon:1; 
+       unsigned int wpt_class:1;
+       unsigned int display:1; 
+       unsigned int category:1; 
+       unsigned int depth:1; 
+       unsigned int proximity:1; 
+       unsigned int temperature:1; 
+       unsigned int city:1;
+       unsigned int state:1;
+       unsigned int facility:1;
+       unsigned int cc:1;
+       unsigned int cross_road:1;
+       unsigned int addr:1;            
+} garmin_fs_flags_t;
+
+typedef struct garmin_fs_s
+{
+       format_specific_data fs;
+       garmin_fs_flags_t flags;
+
+       int protocol;           /* ... used by device (-1 is MapSource) */
+       
+       gbint32 icon;
+       int wpt_class;
+       gbint32 display;
+       gbint16 category;
+       double depth;                   /* depth in meters */
+       double proximity;               /* proximity distance in meters */
+       double temperature;
+       char *city;                     /* city name */
+       char *facility;                 /* facility name */
+       char *state;                    /* state */
+       char *cc;                       /* country code */
+       char *cross_road;               /* Intersection road label */
+       char *addr;                     /* address + number */
+       garmin_ilink_t *ilinks;
+} garmin_fs_t, *garmin_fs_p;
+
+garmin_fs_t *garmin_fs_alloc(const int protocol);
+void garmin_fs_destroy(void *fs);
+void garmin_fs_copy(garmin_fs_t **dest, garmin_fs_t *src);
+char *garmin_fs_xstrdup(const char *src, size_t size);
+
+/* for GPX */
+void garmin_fs_xml_convert(const int base_tag, int tag, const char *cdatastr, waypoint *waypt);
+void garmin_fs_xml_fprint(FILE *ofd, const waypoint *waypt);
+
+/* common garmin_fs utilities */
+
+/* ..convert_category: returns 1=OK; 0=Unable to convert category */
+unsigned char garmin_fs_convert_category(const char *category_name, gbuint16 *category);
+
+/* ..merge_category: returns 1=OK; 0=Unable to convert category */
+unsigned char garmin_fs_merge_category(const char *category_name, waypoint *waypt);
+
+#define GMSD_SECTION_CATEGORIES "Garmin Categories"
+
+#endif